/*
   DEOServer.m created by enoyau on Fri 13-Jan-1995

   You may freely copy, distribute, and reuse the code in this example.
   NeXT disclaims any warranty of any kind, expressed or implied, as to its
   fitness for any particular use.
*/

#import "DEOServer.h"

#import <foundation/NSArray.h>
#import <foundation/NSUtilities.h>
#import <foundation/NSAutoreleasePool.h>
#import <foundation/NSException.h>
#import <remote/NXConnection.h>
#import <remote/NXProxy.h>

@implementation DEOServer

- init
{
    [super init];
    if(wantLog) NSLog(@"DEOServer: init");
    clientDict  = [NSMutableDictionary new];
    return self;
}

- (void)dealloc
{
    if(wantLog) NSLog(@"DEOServer: dealloc");
    [clientDict release];
    [super dealloc];
}

- (oneway)dispatchInformation:(NSDictionary *)info
                       forKey:(NSString *)key
                     userInfo:(NSDictionary *)userInfo
{
    NSMutableArray *array       = [clientDict objectForKey:key];
    NSMutableArray *deadClients = [NSMutableArray array];
    NSEnumerator   *enumerator;
    id <DEOClient> next;

    if(wantLog)
        NSLog(@"DEOServer: Receive information '%@' forKey '%s' user info '%@'",
              [info description],
              [key cString],
              [userInfo description]);
    if(wantLog) NSLog(@"           %d clients to notify", [array count]);

    enumerator = [array objectEnumerator];
    while(next = [enumerator nextObject]) {
        NS_DURING
            [next dispatchInformation:info forKey:key userInfo:userInfo];
        NS_HANDLER
            [deadClients addObject:next];
        NS_ENDHANDLER
    }

    if(wantLog)
        NSLog(@"           %d deads clients detected", [deadClients count]);
    enumerator = [deadClients objectEnumerator];
    while(next = [enumerator nextObject]) {
        [self unregisterClient:next];
    }
    if(wantLog) NSLog(@"---------");
    return;
}

- (oneway)registerClient:(id <DEOClient>)client forKey:(NSString *)key
{
    NSMutableArray *array = [clientDict objectForKey:key];

    if(wantLog) NSLog(@"DEOServer: register client %x for key '%s'\n",
                      (unsigned int)client,
                      [key cString]);

    // A retainCount of 1 means that the client has not been registered
    // before. The client is an autoreleased proxy of a subclass of NSObject.
    if([(NSObject *)client retainCount] == 1) {
        if(wantLog) NSLog(@"           DO registration");
        [(NXProxy *)client setProtocolForProxy:@protocol(DEOClient)];
    }

    if(!array) {
        if(wantLog) NSLog(@"           first client for that key");
        array = [NSMutableArray array];
        [clientDict setObject:array forKey:key];
    }

    // retainCount is incremented by 1 with this operation
    [array addObject:client];

    if(wantLog) NSLog(@"---------");
    return;
}

- (oneway)unregisterClient:(id <DEOClient>)client forKey:(NSString *)key
{
    NSMutableArray *array = [clientDict objectForKey:key];

    if(wantLog) NSLog(@"DEOServer: unregister client %x for key '%s'\n",
                      (unsigned int)client,
                      [key cString]);

    if(array) {
        [array removeObjectIdenticalTo:client]; // To avoid isEqual: on the wire.
        if(![array count]) {
            if(wantLog) NSLog(@"           last client for that key");
            [clientDict removeObjectForKey:key];
        }
    }

    if(wantLog) NSLog(@"---------");
    return;
}

- (oneway)unregisterClient:(id <DEOClient>)client
{
    NSArray *keys = [clientDict allKeys];
    NSEnumerator *enumerator = [keys objectEnumerator];
    NSString *nextKey;

    if(wantLog)
        NSLog(@"DEOServer: unregister client %x\n", (unsigned int)client);

    while(nextKey = [enumerator nextObject]) {
        [self unregisterClient:client forKey:nextKey];
    }
    if(wantLog) NSLog(@"---------");

    return;
}

- (BOOL)hasClient
{
    return [clientDict count] ? YES : NO;
}

@end
